package drds.plus.sql_process.optimizer.cost_esitimater.statistics;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import drds.plus.common.lifecycle.AbstractLifecycle;
import drds.plus.common.model.DataNode;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * 基于repo的{@linkplain StatisticsManager}的委托实现
 */
@Slf4j
public class RepositoryStatisticsManager extends AbstractLifecycle implements StatisticsManager {
    @Override
    public Logger log() {
        return log;
    }

    private static TableStatistics nullTableStatistics = new TableStatistics();
    private static TableIndexStatisticsItem nullTableIndexStatisticsItem = new TableIndexStatisticsItem();
    private RepositoryStatisticsManager delegate;
    private boolean isDelegate;
    private DataNode dataNode;
    private LocalStatisticsManager localStatisticsManager;
    private LoadingCache<String, TableIndexStatisticsItem> indexNameToIndexStatisticsCache = null;
    private LoadingCache<String, TableStatistics> tableNameToTableStatisticsCache = null;
    private boolean useCache;

    protected void doInit() {
        if (!isDelegate) {
            delegate = new RepositoryStatisticsManager();//mysql bdb
            delegate.setDataNode(dataNode);
            delegate.setDelegate(true);
            delegate.init();
            tableNameToTableStatisticsCache = CacheBuilder.newBuilder().maximumSize(1000).expireAfterWrite(30000, TimeUnit.MILLISECONDS).build(new CacheLoader<String, TableStatistics>() {

                public TableStatistics load(String tableName) throws Exception {
                    TableStatistics tableStatistics = delegate.getTableStatistics0(tableName);
                    if (tableStatistics == null) {
                        tableStatistics = nullTableStatistics;
                    }

                    return tableStatistics;
                }
            });
            indexNameToIndexStatisticsCache = CacheBuilder.newBuilder().maximumSize(1000).expireAfterWrite(30000, TimeUnit.MILLISECONDS).build(new CacheLoader<String, TableIndexStatisticsItem>() {

                public TableIndexStatisticsItem load(String indexName) throws Exception {
                    TableIndexStatisticsItem tableIndexStatisticsItem = delegate.getIndexStatistics0(indexName);
                    if (tableIndexStatisticsItem == null) {
                        tableIndexStatisticsItem = nullTableIndexStatisticsItem;
                    }

                    return tableIndexStatisticsItem;
                }
            });

        }

        if (localStatisticsManager != null && !localStatisticsManager.isInited()) {
            localStatisticsManager.init();
        }
    }

    protected void doDestroy() {
        super.doDestroy();

        if (localStatisticsManager != null && localStatisticsManager.isInited()) {
            localStatisticsManager.destroy();
        }

        if (!isDelegate) {
            delegate.destroy();
            indexNameToIndexStatisticsCache.cleanUp();
            tableNameToTableStatisticsCache.cleanUp();
        }

    }

    public TableStatistics getTableStatistics(String tableName) {
        TableStatistics tableStatistics = null;
        if (localStatisticsManager != null) {// 本地如果开启了，先找本地
            tableStatistics = localStatisticsManager.getTableStatistics(tableName);
        }

        if (tableStatistics == null) {
            if (useCache) {
                try {
                    tableStatistics = tableNameToTableStatisticsCache.get(tableName);
                    if (tableStatistics == nullTableStatistics) {
                        return null;
                    }
                } catch (ExecutionException e) {
                    throw new RuntimeException();
                }
            } else {
                return delegate.getTableStatistics0(tableName);
            }
        }

        return tableStatistics;
    }

    public TableIndexStatisticsItem getIndexStatistics(String indexName) {
        TableIndexStatisticsItem tableIndexStatisticsItem = null;
        if (localStatisticsManager != null) {// 本地如果开启了，先找本地
            tableIndexStatisticsItem = localStatisticsManager.getIndexStatistics(indexName);
        }
        if (tableIndexStatisticsItem == null) {
            if (useCache) {
                try {
                    tableIndexStatisticsItem = indexNameToIndexStatisticsCache.get(indexName);
                    if (tableIndexStatisticsItem == nullTableIndexStatisticsItem) {
                        return null;
                    }
                } catch (ExecutionException e) {
                    throw new RuntimeException(e);
                }
            } else {
                return delegate.getIndexStatistics0(indexName);
            }
        }

        return tableIndexStatisticsItem;
    }

    protected TableStatistics getTableStatistics0(String tableName) {
        throw new UnsupportedOperationException("对应repo需要实现");
    }

    protected TableIndexStatisticsItem getIndexStatistics0(String indexName) {
        throw new UnsupportedOperationException("对应repo需要实现");
    }

    public void setDelegate(boolean isDelegate) {
        this.isDelegate = isDelegate;
    }

    public void setDataNode(DataNode dataNode) {
        this.dataNode = dataNode;
    }

    public void setUseCache(boolean useCache) {
        this.useCache = useCache;
    }

    public void setLocalStatisticsManager(LocalStatisticsManager localStatisticsManager) {
        this.localStatisticsManager = localStatisticsManager;
    }

}
